#!/usr/bin/env python
#-*- coding:utf-8 -*-

class Arc(object):
    def __init__(self, start, end, weight=1):
        self.start = start
        self.end = end
        self.weight = weight

    @property
    def start(self):
        return self._start
    
    @start.setter
    def start(self, start):
        self._start = start

    @property
    def end(self):
        return self._end
    
    @end.setter
    def end(self, end):
        self._end = end

    @property
    def weight(self):
        return self._weight
    
    @weight.setter
    def weight(self, weight):
        self._weight = weight

    @property
    def aid(self): #arc id
        return (self.start, self.end)
    
    @property # reverse arc id
    def raid(self):
        return (self.end, self.start)

    def __eq__(self, other):
        if not isinstance(other, Arc):
            return False
        if self.start == other.end and \
            self.end == other.start and \
            self.weight == other.weight:
            return True
        return False
    
    def reverse(self):
        return Arc(self.end, self.start, self.weight)

    def to_tuple(self):
        return tuple(self.start, self.end, self.weight)


class Edge(Arc):
    def __init__(self, start, end, weight=1, two_way=False):
        super(Edge, self).__init__(start, end, weight)
        self.two_way=two_way

    @property
    def two_way(self):
        return self._two_way

    @two_way.setter
    def two_way(self, two_way):
        self._two_way = two_way

    def reverse(self):
        return Edge(self.end, self.start, self.weight, self.two_way)

    def to_tuple(self):
        return (self.end, self.start, self.weight, self.two_way)

    def __eq__(self, other):
        if isinstance(other, Edge):
            return False
        if self.weight != other.weight:
            return False
        if self.two_way != other.two_way:
            return False
        if self.two_way:
            if self.start == other.end and self.end == other.start:
                return True
        if self.start == other.start and self.end == other.end:
            return True
        return False

    def __contains__(self, key):
        if isinstance(key, Arc):
            key = Edge(key.start, key.end, key.weight)
        if isinstance(key, Edge):
            key = key.to_tuple()
        if not isinstance(key, tuple) and len(key) < 2:
            return False
        if self.start == key[0] and self.end == key[1]:
            if len(key) > 3:
                if self.two_way == key[3]:
                    return True
                else:
                    return False
            if len(key) > 2:
                if self.weight == key[2]:
                    return True
                else:
                    return False
            return True
        if self.two_way:
            rkey = list(key)
            rkey[0], rkey[1] = rkey[1], rkey[0]
            rkey = tuple(rkey)
            return rkey in self
        return False


class EdgeSet(dict):
    def __call__(self, key):
        return self.get(key[0], key[1])

    def get(self, start, end):
        key = (start, end)
        if key in self:
            return self[key]
        rkey = (end, start)
        if rkey in self and self[rkey].two_way:
            return self[rkey] #.reverse()
        return None

    def add(self, start, end, weight, two_way=False):
        rkey = (end, start)
        if rkey in self:
            self[rkey].weight = weight
            self[rkey].two_way = True
            return True
        key = (start, end)
        self[key] = Edge(start, end, weight, two_way)
        return True

    def add_edge(self, edge):
        # print("142 add edge", edge)
        self.add(edge.start, edge.end, edge.weight, edge.two_way)

    def edges(self): #merge arcs if possible(key one)
        res = {}
        for key in self.keys():
            rkey = (key[1], key[0])
            if rkey in res and res[rkey].weight == self[key].weight:
                continue
            res[key] = self[key]
        return res.values()

    def reset(self):
        self.clear()
    
    def weight(self, start, end):
        _edge = self.get(start, end)
        if _edge:
            return _edge.weight
        return None

if __name__ == "__main__":
    pass